
#include <BStream>
#include "member_BXmlDocument.h"
#include "member_BXmlNode.h"

using namespace BWE;

member_BXmlDocument::member_BXmlDocument(BXmlDocument* xmldocument)
{
	boss = xmldocument;
	root = 0;
}
member_BXmlDocument::~member_BXmlDocument()
{

}

int member_BXmlDocument::readName(const BString& text, int pos, BString& name)
{
	int begin = pos;
	while (begin < text.size())
	{
		if (!isspace(text[begin]))
			break;
		begin++;
	}
	int end = begin;
	while (end < text.size())
	{
		if (isspace(text[end]))
			break;
		if (text[end] == '>')
			break;
		end++;
	}
	name.reset(text, begin, end);
	return end;
}

bool member_BXmlDocument::overTest(const char* name, BXmlNode* node)
{
	if (name[0] == '/' && node->name() == name + 1)
	{
		return true;
	}
	return false;
}

bool member_BXmlDocument::readNode(BXmlNode* node, const BStream& stream)
{
	BString text;
	char code = 0;
	while (stream.read(code))
	{
		if (code == '<')
		{
			text.simplify();
			if (text.size())
			{
				if (node->childCount())
					node->addText(text);
				else
					node->setText(text);
				text.reset();
			}
		}
		text.append(code);
		if (text.first() == '<' && code == '>')
		{
			if (text.endsWith("/>"))
			{
				BString name;
				int name_end = readName(text, 1, name);
				BXmlNode* child = new BXmlNode(name, node);
				text -= "/>";
				text.remove(0, name_end);
				readAttribs(child, text);
			}
			else if (text.beginsWidth("</"))
			{
				const BString& name = node->name();
				if (!text.contains(name))
					return false;
				break;
			}
			else
			{
				BString name;
				int name_end = readName(text, 1, name);
				BXmlNode* child = new BXmlNode(name, node);
				text.remove(text.size() - 1);
				text.remove(0, name_end);
				readAttribs(child, text);
				readNode(child, stream);
			}
			text.reset();
		}
	}
	return true;
}
void member_BXmlDocument::readAttribs(BXmlNode* node, BString& text)
{
	if (text.empty())
		return;

	text.simplify();
	
	BString label;
	BString value;

	int begin = -1;
	int end = 0;
	while (end < text.size())
	{
		if (text[end] == '\"')
		{
			if (begin < 0)
			{
				begin = end++;
				continue;
			}
			text.substr(value, begin + 1, end);
			text.substr(label, 0, begin);
			label.trimmed();
			if (label.last() != '=')
				return;
			label.remove('=');
			label.trimmed();
			node->setAttrib(label, value);
			text.remove(0, end + 1);
			begin = -1;
			end = 0;
		}
		end++;
	}
}

void member_BXmlDocument::writeNode(BXmlNode* node, int tab)
{
	member_BXmlNode* xml = xmlnode_member(node);
	if (xml->head_pre && !text.endsWith('\n'))
		text << '\n';
	if (text.endsWith('\n'))
		text.append('\t', tab);
	if (node->name().empty())
	{
		if (xml->text.size())
			text << xml->text;
		return;
	}
	text << '<' << node->name();
	if (xml->attribs.size())
	{
		for (int i = 0; i < xml->attribs.size(); i++)
		{
			const AttribPair& attrib = xml->attribs[i];
			text << ' ' << attrib.name << '=' << '\"' << attrib.value << '\"';
		}
	}
	if (xml->text.empty() && xml->children.empty())
	{
		text << "/>";
		if (xml->tail_post)
			text << '\n';
		return;
	}
	text << '>';
	if (xml->head_post)
		text << '\n';
	if (xml->text.size())
	{
		if (text.endsWith('\n'))
			text.append('\t', tab + 1);
		text << xml->text;
	}
	if (xml->children.size())
	{
		for (int i = 0; i < node->childCount(); i++)
		{
			BXmlNode* child = node->child(i);
			writeNode(child, tab + 1);
		}
	}
	if (xml->tail_pre && !text.endsWith('\n'))
		text << '\n';
	if (text.endsWith('\n'))
		text.append('\t', tab);
	text << "</" << node->name() << ">";
	if (xml->tail_post)
		text << '\n';
}